using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Aop.Api;
using Aop.Api.Request;
using Aop.Api.Response;
using Aop.Api.Domain;
using Aop.Api.Util;
using B.S.Medical.Domain.Payment;
using B.S.Medical.Infrastructure.Interface;
using B.S.Medical.Domain.Medical;
using System.Linq;

namespace B.S.Medical.Api.Write.Services.Pay
{
    public interface IAlipayService
    {
        Task<string> CreateAlipayOrderAsync(CreatePayOrderDto dto);
        Task<string> HandleAlipayNotifyAsync(HttpRequest request);
        Task<bool> RefundAsync(RefundPayOrderDto dto);
    }

    public class AlipayService : IAlipayService
    {
        private readonly IConfiguration _config;
        private readonly ILogger<AlipayService> _logger;
        private readonly IBaseRepository<PaymentRecordModel> _paymentRepository;
        private readonly IBaseRepository<PatientBalance> _patientBalanceRepository;

        // 支付宝客户端
        private readonly IAopClient _client;
        
        // 支付宝配置
        private readonly string _appId;
        private readonly string _privateKey;
        private readonly string _publicKey;
        private readonly string _gatewayUrl;
        private readonly string _notifyUrl;
        private readonly string _returnUrl;

        public AlipayService(
            IConfiguration config,
            ILogger<AlipayService> logger,
            IBaseRepository<PaymentRecordModel> paymentRepository,
            IBaseRepository<PatientBalance> patientBalanceRepository)
        {
            _config = config;
            _logger = logger;
            _paymentRepository = paymentRepository;
            _patientBalanceRepository = patientBalanceRepository;
            
            // 从配置中获取支付宝参数
            _appId = _config["Alipay:AppId"];
            _privateKey = _config["Alipay:PrivateKey"];
            _publicKey = _config["Alipay:PublicKey"];
            _gatewayUrl = _config["Alipay:GatewayUrl"] ?? "https://openapi.alipaydev.com/gateway.do"; // 默认沙箱环境
            _notifyUrl = _config["Alipay:NotifyUrl"];
            _returnUrl = _config["Alipay:ReturnUrl"];
            
            // 初始化支付宝客户端
            _client = new DefaultAopClient(_gatewayUrl, _appId, _privateKey, "json", "1.0", "RSA2", _publicKey, "utf-8", false);
        }

        /// <summary>
        /// 创建支付宝订单
        /// </summary>
        public async Task<string> CreateAlipayOrderAsync(CreatePayOrderDto dto)
        {
            try
            {
                _logger.LogInformation($"开始创建支付宝订单: OrderNo={dto.OrderNo}, Amount={dto.Amount}, Subject={dto.Subject}");
                
                // 1. 生成本地订单记录
                var paymentRecord = new PaymentRecordModel
                {
                    OrderNo = dto.OrderNo,
                    PatientId = dto.PatientId,
                    DoctorId = dto.DoctorId,
                    ItemName = dto.Subject,
                    Amount = dto.Amount,
                    IsPaid = false,
                    CreatedTime = DateTime.Now,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now
                };
                
                await _paymentRepository.CreateAsync(paymentRecord);
                
                // 2. 调用支付宝API创建订单
                AlipayTradePrecreateModel model = new AlipayTradePrecreateModel
                {
                    OutTradeNo = dto.OrderNo,
                    TotalAmount = dto.Amount.ToString("0.00"),
                    Subject = dto.Subject,
                    Body = $"医疗费用-{dto.Subject}",
                    TimeoutExpress = "30m" // 30分钟有效期
                };
                
                AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
                request.SetBizModel(model);
                request.SetNotifyUrl(_notifyUrl);
                
                AlipayTradePrecreateResponse response = _client.Execute(request);
                
                if (!response.IsError)
                {
                    _logger.LogInformation($"支付宝订单创建成功: OrderNo={dto.OrderNo}, QrCode={response.QrCode}");
                    return response.QrCode; // 返回二维码链接
                }
                else
                {
                    _logger.LogError($"支付宝订单创建失败: {response.SubMsg}");
                    throw new Exception($"支付宝下单失败: {response.SubMsg}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"创建支付宝订单异常: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 处理支付宝异步通知
        /// </summary>
        public async Task<string> HandleAlipayNotifyAsync(HttpRequest request)
        {
            try
            {
                _logger.LogInformation("收到支付宝支付回调");
                
                // 1. 获取回调参数
                Dictionary<string, string> parameters = new Dictionary<string, string>();
                
                // 将请求参数转换为字典
                foreach (var key in request.Form.Keys)
                {
                    parameters.Add(key, request.Form[key]);
                }
                
                // 2. 验证签名
                bool signVerified = AlipaySignature.RSACheckV1(parameters, _publicKey, "utf-8", "RSA2", false);
                
                if (!signVerified)
                {
                    _logger.LogWarning("支付宝回调签名验证失败");
                    return "failure";
                }
                
                // 3. 处理业务逻辑
                string outTradeNo = parameters["out_trade_no"]; // 商户订单号
                string tradeNo = parameters["trade_no"]; // 支付宝交易号
                string tradeStatus = parameters["trade_status"]; // 交易状态
                
                _logger.LogInformation($"支付宝回调: OutTradeNo={outTradeNo}, TradeNo={tradeNo}, TradeStatus={tradeStatus}");
                
                // 查询订单
                var paymentRecord = _paymentRepository.GetAll()
                    .Where(p => p.OrderNo == outTradeNo && !p.IsDeleted)
                    .FirstOrDefault();
                
                if (paymentRecord == null)
                {
                    _logger.LogWarning($"未找到订单: {outTradeNo}");
                    return "failure";
                }
                
                // 判断交易状态
                if (tradeStatus == "TRADE_SUCCESS" || tradeStatus == "TRADE_FINISHED")
                {
                    // 更新订单状态
                    if (!paymentRecord.IsPaid)
                    {
                        paymentRecord.IsPaid = true;
                        paymentRecord.PayStatus = tradeStatus;
                        paymentRecord.PayTradeNo = tradeNo;
                        paymentRecord.PayTime = DateTime.Now;
                        paymentRecord.UpdateTime = DateTime.Now;
                        
                        await _paymentRepository.UpdateAsync(paymentRecord);
                        
                        _logger.LogInformation($"订单支付成功: {outTradeNo}");
                    }
                    else
                    {
                        _logger.LogInformation($"订单已处理: {outTradeNo}");
                    }
                }
                
                return "success";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"处理支付宝回调异常: {ex.Message}");
                return "failure";
            }
        }

        /// <summary>
        /// 申请退款
        /// </summary>
        public async Task<bool> RefundAsync(RefundPayOrderDto dto)
        {
            try
            {
                _logger.LogInformation($"开始申请退款: OrderNo={dto.OrderNo}, RefundAmount={dto.RefundAmount}");
                
                // 1. 查询订单
                var paymentRecord = _paymentRepository.GetAll()
                    .Where(p => p.OrderNo == dto.OrderNo && p.IsPaid && !p.IsDeleted)
                    .FirstOrDefault();
                
                if (paymentRecord == null)
                {
                    _logger.LogWarning($"未找到已支付订单: {dto.OrderNo}");
                    throw new Exception("未找到已支付订单");
                }
                
                // 2. 调用支付宝退款接口
                AlipayTradeRefundModel model = new AlipayTradeRefundModel
                {
                    OutTradeNo = dto.OrderNo,
                    RefundAmount = dto.RefundAmount.ToString("0.00"),
                    RefundReason = dto.Reason ?? "用户申请退款"
                };
                
                AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
                request.SetBizModel(model);
                
                AlipayTradeRefundResponse response = _client.Execute(request);
                
                if (response.IsError)
                {
                    _logger.LogError($"申请退款失败: {response.SubMsg}");
                    throw new Exception($"退款申请失败: {response.SubMsg}");
                }
                
                // 3. 更新订单状态
                string refundTradeNo = $"RF{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}";
                
                paymentRecord.RefundStatus = "已退款";
                paymentRecord.RefundAmount = dto.RefundAmount;
                paymentRecord.RefundTradeNo = refundTradeNo;
                paymentRecord.RefundTime = DateTime.Now;
                paymentRecord.UpdateTime = DateTime.Now;
                
                await _paymentRepository.UpdateAsync(paymentRecord);
                
                // 4. 更新患者余额
                var patientBalance = _patientBalanceRepository.GetAll()
                    .Where(b => b.PatientId == paymentRecord.PatientId && !b.IsDeleted)
                    .FirstOrDefault();
                
                if (patientBalance != null)
                {
                    patientBalance.Balance += dto.RefundAmount;
                    patientBalance.LastUpdatedTime = DateTime.Now;
                    patientBalance.UpdateTime = DateTime.Now;
                    patientBalance.Remark = $"退款：{dto.RefundAmount}元，订单号：{dto.OrderNo}";
                    
                    await _patientBalanceRepository.UpdateAsync(patientBalance);
                }
                else
                {
                    // 如果没有余额记录，创建一个新的
                    patientBalance = new PatientBalance
                    {
                        PatientId = paymentRecord.PatientId,
                        Balance = dto.RefundAmount,
                        LastUpdatedTime = DateTime.Now,
                        UpdateTime = DateTime.Now,
                        Remark = $"退款：{dto.RefundAmount}元，订单号：{dto.OrderNo}"
                    };
                    
                    await _patientBalanceRepository.CreateAsync(patientBalance);
                }
                
                _logger.LogInformation($"退款成功: OrderNo={dto.OrderNo}, RefundAmount={dto.RefundAmount}");
                
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"申请退款异常: {ex.Message}");
                throw;
            }
        }
    }

    /// <summary>
    /// 支付下单DTO
    /// </summary>
    public class CreatePayOrderDto
    {
        /// <summary>
        /// 订单号
        /// </summary>
        public string OrderNo { get; set; }
        
        /// <summary>
        /// 支付金额
        /// </summary>
        public decimal Amount { get; set; }
        
        /// <summary>
        /// 订单标题
        /// </summary>
        public string Subject { get; set; }
        
        /// <summary>
        /// 患者ID
        /// </summary>
        public int PatientId { get; set; }
        
        /// <summary>
        /// 医生ID
        /// </summary>
        public int DoctorId { get; set; }
    }

    /// <summary>
    /// 退款DTO
    /// </summary>
    public class RefundPayOrderDto
    {
        /// <summary>
        /// 订单号
        /// </summary>
        public string OrderNo { get; set; }
        
        /// <summary>
        /// 退款金额
        /// </summary>
        public decimal RefundAmount { get; set; }
        
        /// <summary>
        /// 退款原因
        /// </summary>
        public string Reason { get; set; }
    }
} 